package com.qmerak.common;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemHeaders;
import org.apache.commons.fileupload.FileItemHeadersSupport;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 同一个session可以根据from的fromID同时保存多个from的进度，
 * 每个FromProgressModel对应一个FromProgressModel的实例<br>
 * 
 * 每个request对应一个FromProgressModel
 * 
 * @author hexin
 * 
 */
public class ServletFileUploadExt extends ServletFileUpload {
	private static final Logger LOG = LoggerFactory.getLogger(ServletFileUploadExt.class);

	/**
	 * itemMap 用来保存每个form中文件input的位置
	 */
	private HttpServletRequest request;
	private FromProgressModel fromProgressModel;

	public static String FORM_ID = "formId"; // 和js对应
	public static String SESSION_FORM_MAP = "_from_map";// 和session对应

	public ServletFileUploadExt(FileItemFactory fileItemFactory, FromProgressModel fromProgressModel) {
		super(fileItemFactory);
		this.fromProgressModel = fromProgressModel;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<FileItem> parseRequest(HttpServletRequest request) throws FileUploadException {

		this.request = request;
		return super.parseRequest(request);
	}

	@SuppressWarnings("unchecked")
	public List<FileItem> /* FileItem */parseRequest(RequestContext ctx) throws FileUploadException {

		List<FileItem> items = new ArrayList<FileItem>();
		boolean successful = false;
		try {
			FileItemIterator iter = getItemIterator(ctx);
			FileItemFactory fac = getFileItemFactory();
			if (fac == null) {
				throw new NullPointerException("No FileItemFactory has been set.");
			}
			int k = 0;// see ProgressListener !!The number of the field, which
						// is currently being read. (0 = no item so far, 1 =
						// first item is being read, ...)
			while (iter.hasNext()) {
				k++;
				final FileItemStream item = iter.next();
				// fileName input value
				final String fileName = item.getName();
				// input value
				final String fieldName = item.getFieldName();
				FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);
				items.add(fileItem);

				// add by hexin
				if (!item.isFormField()) {
					fromProgressModel.addItem(k, fieldName);
					LOG.debug("fromProgressModel add  fieldName :>> " + fieldName);
				}

				try {
					Streams.copy(item.openStream(), fileItem.getOutputStream(), true);
				} catch (FileUploadIOException e) {
					throw (FileUploadException) e.getCause();
				} catch (IOException e) {
					throw new IOFileUploadException("Processing of " + MULTIPART_FORM_DATA + " request failed. " + e.getMessage(), e);
				}

				// add by hexin
				if (item.isFormField()) {
					if (FORM_ID.equals(fieldName)) {
						String itemValue = fileItem.getString();
						LOG.debug("FORM_ID >> " + itemValue);
						HttpSession session = request.getSession();
						Map<String, FromProgressModel> fromProgressModelMap = (Map<String, FromProgressModel>) session
								.getAttribute(SESSION_FORM_MAP);
						if (fromProgressModelMap == null) {
							fromProgressModelMap = new HashMap<String, FromProgressModel>();
							session.setAttribute(SESSION_FORM_MAP, fromProgressModelMap);
							LOG.debug("SESSION_FORM_MAP is not exists in session ,put new one >> ");
						}
						fromProgressModelMap.put(itemValue, fromProgressModel);
					}
				}
				if (fileItem instanceof FileItemHeadersSupport) {
					final FileItemHeaders fih = item.getHeaders();
					((FileItemHeadersSupport) fileItem).setHeaders(fih);
				}
			}
			successful = true;
			return items;
		} catch (FileSizeLimitExceededException e) {
			throw e;
		} catch (FileUploadIOException e) {
			throw (FileUploadException) e.getCause();
		} catch (IOException e) {
			throw new FileUploadException(e.getMessage(), e);
		} finally {
			if (!successful) {
				for (Iterator<FileItem> iterator = items.iterator(); iterator.hasNext();) {
					FileItem fileItem = (FileItem) iterator.next();
					try {
						fileItem.delete();
					} catch (Throwable e) {
						// ignore it
					}
				}
			}
		}
	}
}
